import { useLocaleProvide } from '@hooks/useLocale'
import { useFormMultiLanguage } from '@hooks/useFormMultiLanguage'
import useJsCodeBlock from '@hooks/useJsCodeBlock'
import draggable from 'vuedraggable';

import FormField from './FormField';
import Platform from '../../platform';
import normalizeWheel from '@src/util/normalizeWheel';
import i18n from '@src/locales'

import * as config from './config'

import {
  FieldManager,
  PreviewComponents,
  SettingComponents
} from './components';
import RelationOptionsModal from './common/components/RelationOptionsModal/RelationOptionsModal.tsx';
import {
  cloneDeep, 
  isEmpty,
  isNumber
} from 'lodash';

import { isSelect, getSelectOptionMax, isDateField, isDatetimeField } from './util'
import { checkUser, deleteField, getAllFields } from '@src/api/TaskApi.ts';
import { getLogisticsQuotaDetail } from '@src/api/FieldApi';

import { getType } from '@src/api/ProductV2Api';
import {deleteCardField} from '@src/api/SettingTaskApi';
import { deleteEventField, deleteEventCardField } from '@src/api/SettingServiceEventApi';
import * as CustomerApi from '@src/api/CustomerApi';
import * as ProductApi from '@src/api/ProductApi';
import { isBasicEdition, isBasicEditionHidePart, isBasicEditionHideProduct, isBasicEditionHideServe } from '@shb-lib/version'
import { isMultiLangModules } from '@src/component/util/multiLang/index';
import { allAmountFieldNameList } from '@src/util/currency';
import { getActivateControlFields } from '@src/component/form/util/index.js'
import { postPage } from 'pub-bbx-utils'
/* enum */
import { FieldTypeMappingEnum } from '@model/enum/FieldMappingEnum';
import TableNameEnum from '@model/enum/TableNameEnum.ts';
import { SELECT_OPTION_MAX } from '@src/component/form/config'

import { findParentElementWithClassName } from '@src/util/dom';

import { getProductFieldList, getMaterialAllFields, getServiceProviderFields, getProductMaterialFields, getTaskMaterialFields } from '@src/api/FieldApi.ts';
import { getSparepartFields } from '@src/api/SparePart.js';
import { servicePriceListInfo } from '@src/api/ServicePriceApi.js';


import SetLanguage from '@src/modules/setting/serviceEvent/serviceEventTypeSetting/flow/components/SetLanguage.vue'
import BaseLanguageDropdown from '@src/component/common/BaseLanguageDropdown/index'
import FormCurrencyType from '@src/component/form/components/FormCurrencyType/FormCurrencyType.vue';
/* mixin */
import FormDesignMixin from '@src/component/form/mixin/form.design'

import * as FormUtil from './util';

const { internationalGray } = useFormMultiLanguage()

/**
 * 展示是否必填项的字段
 * manager: 客户负责人
 * productManager: 产品负责人
 */
const SHOW_IS_NULL_FIELD_COMP = ['synergies', 'manager', 'managerPerson', 'productDesc', 'productVideo', 'productPic', 'thumbnail', 'productExplain', 'product_menu_part', 'product_menu_wiki', 'productManager'];
// 关联字段禁用的类型
const RELATION_DISABLE_FIELDS = ['attachment', 'autograph', 'separator', 'info',  FieldTypeMappingEnum.JsCodeBlock];

/** 创建字段预览组件 */
export function createPreviewComp(h, field){
  let currFieldId = field._id;
  let previewComp = FieldManager.findField(field.formType);

  if(previewComp == null){
    console.warn(`[not implement]: ${field.displayName}(${field.fieldName}): ${field.formType}. `)
    return null;
  }

  // 根据字段配置创建预览内容
  // todo 临时解决
  if (!previewComp) return;

  // TODO 隐藏字段不渲染
  if(field.isHidden == 1) return;

  // if (!this.isBasicVersionShow && field.fieldName === 'customer' && field.setting.customerOption) {
  //   field.setting.customerOption.product = false;
  // }

  let fieldPreview = h(previewComp.preview, {
    'class': 'form-design__ghost',
    props: { field, setting: previewComp}
  });

  let previewClass = {
    'form-design-preview': true,
    'form-design-selected': this.currField && (currFieldId == this.currField._id), // 被选中
    'form-design-dragging': field.dragging,
  }
  if (field?.setting?.autoSerialNumber) {
    field.defaultTips = i18n.t('common.form.tip.moduleWillCreateAfterSetTip1', {module:field.displayName})
  }
  let zhongxian = <div class="form-design-divider-separator" role="separator"></div>
  let deleteDom = <div class="form-design-preview-delete form-design-preview-btn" onClick={e => this.deleteField(field)}>
    <el-tooltip class="item" effect="dark" content={i18n.t('common.base.delete')} placement="top">
      <i class="iconfont icon-shanchu-copy"></i>
    </el-tooltip>
  </div>;
  return (
    <div class={previewClass} key={currFieldId}
      onMousedown={e => this.beginSort(field, e)}>
      {fieldPreview}
      {(field.isSystem == 0 || previewComp.forceDelete)
      && <div class="form-design-operation">
        <div class="form-design-preview-hidden form-design-preview-btn" onClick={e => this.hiddenField(field)}>
          <el-tooltip class="item" effect="dark" content={i18n.t('common.base.hide')} placement="top">
            <i class="iconfont icon-fdn-hidden"></i>
          </el-tooltip>
        </div>
        {!(field.setting && field.setting.notEdit) && zhongxian}
        {!(field.setting && field.setting.notEdit) && deleteDom}
      </div>}
      <div class="form-design-cover"></div>
    </div>
  )
}

/** 获取设置组件组件名，如果返回null，渲染默认组件 */
function getSettingComp(field, comp){
  // 先检测是否有扩展设置
  let extend = comp.extend || {};
  let key = `${this.mode}_${field.fieldName}_setting`;

  // TODO: 当fieldName不固定且是系统字段
  let systemKey = `${this.mode}_${field.formType}_setting`;
  if(extend[key] || extend[systemKey]) return extend[key] || extend[systemKey];


  // 系统字段默认设置
  let arr = ['quality_info', 'quality', 'engineerQualification', 'serviceProviderQualification', 'subSucCase', 'subCertifications', 'subServiceItem', 'tagLabel', 'imageDisplay', 'materialsBill','estimatedMileage','actualMileage','taskEstimatedMileage', 'productWarrantyService', 'currencyType', 'knowledge', 'subMaterials', 'newFaultLibrary', 'relatedServiceItem']

  // 服务备注表单增加产品控件
  if (this.mode == 'remark') {
    arr.push('remarkProduct')
  }

  // taskNo 开利项目工单编号需要灰度控制
  if (this.isCustomTaskNo) {
    arr.push('taskNo')
  }
  if(this.isSparePartsReturnExpense) {
    arr.push('sparePartsReturnExpense')
  }
  if(field.isSystem == 1 && (!arr.includes(field.formType))) return null;
  return comp.setting;
}

/** 创建字段设置组件 */
function createSettingComp(h, field){
  if(null == field) return null;
  if(field.isHidden == 1) return null;

  let formType = field.formType;
  let comp = FieldManager.findField(formType);

  if (formType === 'tags') { // 线跟随客户走，用select
    comp = FieldManager.findField('select');
  }

  if(null == comp) return null;

  let compName = getSettingComp.call(this, field, comp);


  const isForceDeleteFields = ['serviceStartTime', 'serviceEndTime', 'serviceMoney', 'productCompleteAddress', 'currencyType']
  let props = {
    field,
    setting: comp,
    mode: this.mode,
    fields: this.value,
    templateId: this.templateId,
    templateName: this.templateName,
    showJsCodeBlock: this.showJsCodeBlock,
    isShowRelationTask: this.isShowRelationTask,
  };

  if(field.formType === 'select') {
    field.setting = field.setting || {}
    field.setting.customizedSelectOptionMax = this.customizedSelectOptionMax;
  }
  // 是否展示货币组件 是国际化 且 为金额字段
  const isShowCurrency = internationalGray && allAmountFieldNameList.includes(field.fieldName);

  const { locale: formPreviewLocale } = useLocaleProvide('formPreviewLocale');

  let _this = this;
  let dom = function(com){
    return h(com, {
      props,
      key: field.fieldName,
      on: {
        input: event => {

          if(field.formType === 'info'){
            field?.placeHolderLanguage?.[formPreviewLocale.value] && (field.placeHolderLanguage[formPreviewLocale.value] = event.value);
          }

          if (event.prop == 'dependencies') {
            let { operate, value } = event;

            if (operate == 'update') _this.updateDependencies(value);
            if (operate == 'delete') _this.deleteDependencies(field, false);
            return;
          }

          if (event.prop == 'isMulti') {
            if(field.fieldMappingForm?.sourceField) {
              let obj = { ...field.fieldMappingForm }
              obj.sourceField = ''

              _this.$set(field, 'fieldMappingForm', obj)
            }
            if (event.value) {
              _this.deleteDependencies(field);
            }
          }
          // 批量更新
          if (event.prop === 'assign') {
            delete event.prop
            for (let [key, value] of Object.entries(event)) {
              if (key === 'setting') {
                for (let [settingKey, settingValue] of Object.entries(event.setting)) {
                  _this.$set(field.setting, settingKey, settingValue);
                }
              } else {
                _this.$set(field, key, value);
              }
            }
            return
          }
          if (event.isSetting) {
            _this.$set(field.setting, event.prop, event.value);
          } else {
            _this.$set(field, event.prop, event.value);
          }
        },
        updateOptions: event => {
          _this.updateOptions(field, event);
        },
      }
    });
  }
  if(null == compName) return (
    <div class="form-setting-panel">
      <h3 class="form-setting-panel-title">{field.displayName}</h3>
      <p class="form-design-warning">{!isForceDeleteFields.includes(field.fieldName) ? i18n.t('common.form.tip.systemTemplateTips') : i18n.t('common.form.tip.systemTemplateCantDeleteTips')}</p>
      {
        // createTitle(h, field, comp, this)
        // 描述信息
        this.mode === 'product_register' && ['userName', 'userPhone'].includes(field.fieldName) && createDescribed(h, field)
      }

      {/* 合同生效，失效日期支持修改标题 */}
      {
        this.mode === 'contract' && ['effectiveTime', 'invalidTime'].includes(field.fieldName) && (createTitle(h, field, comp, this) && createDateFormatSetting(h, field, comp, this))
      }
      {
        (
          this.mode === 'contract' ?
          ['otherAmount', 'discountAmount', 'tags', 'managerPerson', 'serviceMoney', 'contractAmount', 'quotationAmount', 'procureAmount'].includes(field.fieldName) :
          SHOW_IS_NULL_FIELD_COMP.includes(field.fieldName)
        )
        && createRequired(h, field, this)
      }
      {(this.mode === 'service_provider' || this.mode === 'service_engineer') && (field.formType !== 'separator') && field.showIsNull === 1 && createRequired(h, field, this) }
      { field.fieldName === 'catalogNum' && createAutoGeneration(h, field) }
      {
        this.mode === 'contract'
          && field.isSystem
          && !['contractName', 'contractNo', 'templateName'].includes(field.fieldName)
          && createFieldAuth(h, field, this, { search: true })
      }
      {/* 工作日志 消耗工时&剩余工时 */}
      { this.mode === 'projectWorkLog' && field.fieldName === 'workContent' && createRequired(h, field, this)}
      { field.fieldName === 'contractAmount' && internationalGray && createdCheckCurrency(h, field, this) }
      {field.fieldName === 'productCompleteAddress' && dom(comp.setting)}
      { isShowCurrency && createdDefaultCurrency(h, field, this) }
      {/* 服务开始时间 服务结束时间 */}
      { ['serviceStartTime', 'serviceEndTime'].includes(field.fieldName) && createDateFormatSetting(h, field, comp, this)}
      {/* 如果之后上级客户需要必填则放开 */}
      {/* { this.mode === 'customer' && field.fieldName === 'parentCustomer' && createRequired(h, field, this) } */}
    </div>
  );


  if(isSelect(field) || field.formType == 'quality') props.getContext = () => this;
  let type = this.mode == 'product_register' && field.registerFieldFlag;
  let mapType = this.mode == 'customer' && (field.fieldName == 'customerAddress' || field.fieldName == 'tags')
  let effectiveItem = ['text', 'textarea', 'number', 'select', 'cascader', 'attachment', 'user', 'date', 'datetime', 'phone', 'email', 'address'].includes(formType)
  let map = this.isOpenRegister && (this.mode == 'product' || this.mode == 'customer') && !mapType && effectiveItem && !isBasicEdition();


  let modeName = {
    customer: i18n.t('common.form.type.customer'),
    product: i18n.t('common.form.type.product')
  }

  let regesterDom = <div class='form-setting-panel' style='padding-top:0;margin-top:-24px'>
    <h4 class="form-common-setting-title" style="margin-bottom: 0;"><span class="form-common-setting-title-name">{i18n.t('common.form.setting.productRegisterSymbol')}</span></h4>
    {createProductRegister(h, field, this)}
  </div>
  let mapDom = <div class='form-setting-panel' style='padding-top:0;margin-top:-24px'>
    <h4 class="form-common-setting-title"><span class="form-common-setting-title-name">{i18n.t('common.form.setting.dataSourceSet', {module: modeName[_this.mode] })}</span></h4>
    { createMap(h, field, this)}
    {field.fieldName === 'qrcodeId' && createShow(h, field, this)}{/* 要判断是否是二维码字段 */}
  </div>
  return (
    <div >
      {dom(compName)}
      {type && regesterDom}
      {map && mapDom}
    </div>
  )
}

function defaultInputFn(value, prop, isSetting = false, field, _this) {
  if (isSetting) {
    _this.$set(field.setting, prop, value);
  } else {
    _this.$set(field, prop, value);
  }
}

function createFieldAuth(h, field, _this, setting) {
  const bool = field.fieldName !== 'contractAmount';
  let previewClass = {
    'form-setting-group': bool,
    'form-label-margin': !bool,
    'form-setting-item': true
  }
  
  // <h4 class="form-item-title">字段权限</h4>
  return (
    <div class={ previewClass }>
      <div class="form-item-box">
        {
          setting.visible && h('form-visible-setting', {
            props: { field },
            on: {
              input: (value, prop, isSetting) => {
                defaultInputFn(value, prop, isSetting, field, _this)
              }
            }
          })
        }
        {
          setting.search && h('form-search-setting', {
            props: { field },
            on: {
              input: (value, prop, isSetting) => {
                defaultInputFn(value, prop, isSetting, field, _this)
              }
            }
          })
        }
      </div>
    </div>
  )
}

/**
 * 创建日期相关设置项（系统字段）
 */
function createDateFormatSetting(h, field, setting, _this) {
  return h('form-date-format-setting', {
    props: { field, setting},
    on: {
      input: ({ isSetting, prop, value}) => {
        isSetting ? _this.$set(field.setting, prop, value) : _this.$set(field, prop, value);
      }
    }
  })
}

/**
 * 创建描述信息
 */
function createTitle(h, field, setting, _this) {
  return h('form-title-setting', {
    props: { field, setting},
    on: {
      input: event => {
        let el = event.target;
        let prop = el.dataset.prop;
        let value = el.value;
        _this.$set(field, prop, value);
      }
    }
  })
}

/**
 * 创建描述信息
 */
function createDescribed(h, field) {
  return h('form-describe-setting', {
    props: {
      field
    },
    on: {
      input: (event) => {
        let el = event.target;
        let value = el.value;
        let prop = el.dataset?.prop || 'placeHolder'
        field[prop] = value
      }
    },
  });
}

/**
 * 创建必填项
 */
function createRequired(h, field, _this) {
  return h('el-checkbox', {
    props: {
      value: field.isNull,
      trueLabel: 0,
      falseLabel: 1,
      disabled:!!(_this.mode == 'product_register' && field.isRegister)
    },
    on: {
      input: (value, prop) => {
        field.isNull = value;
      }
    },
  }, [i18n.t('common.base.isRequire')]);
}

/**
 * 创建映射关系
 */
function createMap(h, field, _this) {
  return h('field-map-setting', {
    props: {
      approveSetting: field.fieldMappingForm,
      list:_this.mapList,
      field
    },
    on: {
      fieldChange: (value, prop) => {
        field.fieldMappingForm.sourceField = value;
        // field.fieldMappingForm.sourceTable = 'register'
      },
      tableChange: (value, prop) => {
        // field.fieldMappingForm.sourceField = value;
        field.fieldMappingForm.sourceTable = value
      }
    },
  });
}
/**
 * 创建必填项
 */
function createShow(h, field, _this) {
  return h('el-checkbox', {
    props: {
      value: field.isHidden,
      trueLabel: 0,
      falseLabel: 1,
      disabled:!!(_this.mode == 'product_register' && field.isRegister)
    },
    on: {
      input: (value, prop) => {
        field.isHidden = value;
      }
    },
  }, [i18n.t('common.base.display')]);
}
/**
 * 创建是否是产品注册字段
 */
function createProductRegister(h, field, _this) {
  let dom = <el-tooltip placement="top" popper-class="form-msg-setting-tooltip">
    <div slot="content">
      <div class="tooltip">{i18n.t('common.form.tip.productReTips1')}</div>
    </div>
    <i class="iconfont icon-question"></i>
  </el-tooltip>
  return (
    <div>
      <div class="form-setting-group" style="margin-bottom: 0">
        {
          h('el-checkbox', {
            props: {
              value: field.isRegister,
              trueLabel: 1,
              falseLabel: 0,
            },
            style: {
              marginRight: '54px'
            },
            on: {
              input: (value, prop) => _this.checkField(value, field, _this.productRegisterDisplayName)
            },
          }, [i18n.t('common.form.setting.productRegisterCreateLabel'), dom])
        }
        {createRequired(h, field, _this)}
        {field.fieldName === 'qrcodeId' && createShow(h, field, _this)}{/* 要判断是否是二维码字段 */}
      </div>

    </div>
  )
}
/**
 * 创建启用自动编号项
 */
function createAutoGeneration(h, field) {
  return (
    <div>
      <div class="form-setting-group">
        {
          h('el-checkbox', {
            props: {
              value: field.setting.autoGeneration,
              trueLabel: 1,
              falseLabel: 0,
            },
            on: {
              input: (value, prop) => {
                field.setting.autoGeneration = value;
                field.defaultTips = value ? i18n.t('common.form.tip.moduleWillCreateAfterSetTip1', {module:field.displayName}) : ''
              }
            },
          }, [i18n.t('common.form.setting.createAutoGenerationLabel')])
        }
      </div>
      <p class="form-select-logical-tip">
        {i18n.t('common.form.tip.moduleWillCreateAfterSetTip2', {module:field.displayName})}
      </p>
    </div>
  )
}

/**
 * 创建默认币种项
 */
function createdDefaultCurrency(h, field, _this) {
  field.setting.defaultCurrency = field.setting?.defaultCurrency || 'CNY';
  _this.defaultCurrency = field.setting.defaultCurrency;

  return (
    <div class="form-setting-group">
      <h4 class="form-item-title">{ i18n.t('common.currency.defaultCurrency') }</h4>
      <div class="form-currency-setting">
        {
          h('form-currency-type', {
            props: {
              field,
              value: _this.defaultCurrency,
            },
            on: {
              input: (value, prop) => {
                field.setting.defaultCurrency = value;
                _this.defaultCurrency = value;
              }
            }
          })
        }
      </div>
    </div>
  )
}
/**
 * 创建默认币种项
 */
function createdCheckCurrency(h, field, _this) {
  if(!isNumber(field.setting?.checkCurrency)) field.setting.checkCurrency = 1;

  return (
    <div class="form-setting-group">
      {
        h('form-check-currency-setting', {
          props: {
            field,
          },
          on: {
            input: (value, prop, isSetting) => {
              defaultInputFn(value, prop, isSetting, field, _this)
            }
          }
        })
      }
    </div>
  )
}

/**
 * 判断元素是否可见
 * @param {*} el 判断的元素
 */
function isVisibility(el, container){
  if (!el || !container) return true;

  let min = container.scrollTop;
  let max = min + container.offsetHeight;

  return min <= el.offsetTop && (el.offsetTop + el.offsetHeight) <= max;
}

/** 检测元素是否在容器内 */function isInContainer(elRect, containerRect){
  return !(
    elRect.right < containerRect.left // 检测是否在容器左边
    || elRect.left > containerRect.right // 检测是否在容器右边
    || elRect.top > containerRect.bottom // 检测是否在容器下边
    || elRect.bottom < containerRect.top // 检测是否在容器上边
  );
}

/** 获取拖拽显示模板 */
function getTemplate(el){
  if(el.classList.contains('form-design__ghost')){
    return el.outerHTML;
  }

  let tmp = el.querySelectorAll('.form-design__ghost');
  let outerHTML = '';
  if (tmp.length > 1) {
    tmp.forEach(item => {
      outerHTML += item.outerHTML
    })
  }

  return outerHTML;
}
import SettingMixin from '@src/component/form/mixin/setting';
import { getRootWindow } from '@src/util/dom'
import { isFalsy, isNotUndefined } from '@src/util/type';
import { getRoleServiceTree } from "@src/api/RoleApi";

const FormDesign = {
  name: 'form-design',
  mixins: [
    SettingMixin,
    FormDesignMixin
  ],
  props: {
    mode: {
      type: String,
      default: 'base'
    },
    value: {
      type: Array,
      default: () => []
    },
    /** 最大字段数量 */
    max: {
      type: Number,
      default: config.FORM_FIELD_MAX
    },
    /** 公共字段 */
    commonFields: {
      type: Array,
      default: () => ([])
    },
    relationFieldOptions: { // 关联查询字段关联项数据
      type: Object,
      default: () => ({})
    },
    isOpenRegister: {
      type: Boolean,
      default: false
    },
    templateId: {
      type: String,
      default: ''
    },
    templateName: {
      type: String,
      default: ''
    },
    isShowRelationTask: { // 是否显示工单表单引用字段字段
      type: Boolean,
      default: false
    },
    isDisableCommonField: { // 是否禁止修改公用字段
      type: Boolean,
      default: false
    },
  },
  setup(){
    const { locale: formPreviewLocale, setFormPreviewLocale } = useLocaleProvide('formPreviewLocale');
    const { isOpenMultiLanguage, languagesList, internationalGray } = useFormMultiLanguage()
    function changeLocale(e){
      setFormPreviewLocale(e)
    }

    return {
      formPreviewLocale,
      changeLocale,
      isOpenMultiLanguage,
      languagesList,
      internationalGray,
    };
  },
  data(){
    let modeFields = FieldManager.findModeFields(this.mode, this.isOpenQuality, this.isShowRelationTask);
    // 获取被 role_auth 过滤掉但是要显示的控件
    let roleList = this.genRoleList(modeFields);
    modeFields = modeFields.concat(roleList);
    let hasSystemField = false;
    let availableFields = [];

    modeFields.forEach(item => {
      let field = FieldManager.findField(item);
      if(roleList?.includes(field.formType)) field = FieldManager.generatePaidTags(field)
      if(null == field) return;

      if(field.isSystem == 1) hasSystemField = true;
      availableFields.push(field)
    })

    return {
      isShow: true,
      // 物料清单关联字段
      taskSystemFields: [],
      // 角色列表
      roleList:[],
      // 服务商角色列表
      providerRoles:[],
      // 物料清单关联字段
      materialFiels: [],
      // 产品关联字段
      productFields: [],
      // 服务商子表单关联字段
      serviceProviderFields: [],
      // 备件关联字段
      sparePartFields: [],
      // 服务项目关联字段
      serviceItemFields: [],
      // 当前模式下可用字段
      availableFields,
      // 是否显示系统字段tab
      hasSystemField,
      // 当前显示的字段 0 -- 基础组件  1 -- 系统组件
      fieldGroup: 0,
      // 拖拽相关
      $dragEvent: {
        target: null, // 正在被拖拽的元素
        offsetX: 0, // 鼠标与拖拽元素左边界距离
        offsetY: 0, // 鼠标与拖拽元素上边界距离
        prevClientY: 0, // 上一点的y坐标
        direction: 0, // 移动的方向 1 -- 向下  -1 -- 向上
        ghostEl: null,
        containerEl: null, // 字段容器
        mode: null, // 拖拽模式 sort -- 排序 insert -- 添加字段
        insertFieldOption: null // 待插入字段的选项
      },
      // 当前选择的字段
      currField: null,
      // 容器是否静默，不响应hover
      silence: false,
      // 插入的字段
      insertedField: null,
      // 插入前的值
      originValue: null,
      autographMax: config.AUTOGRAPH_MAX_LENGTH_MAX,
      richTextFieldsMax:config.RICHTEXT_LENGTH_MAX,
      show: false,
      // 修改公共字段配置
      fieldSettingModal: {
        visible: false,
        pending: false,
        backupField: {} // 备份数据
      },
      mapList:[],
      // 是否处于拖拽中
      dragging: false,
      relationField: {}, // 关联项字段
      relationOptions: { // 关联查询字段关联项数据
        customerFields: [],
        productFields: []
      },
      relationOptionsMap: {
        relationCustomer: 'customerFields',
        relationProduct: 'productFields',
      },
      // 单个表单最多3个连接器字段
      maxConnectorFields: 10,
      // 定制化需求，需要从接口获取下拉选项的数量限制
      customizedSelectOptionMax: SELECT_OPTION_MAX,
      defaultCurrency: 'CNY', // 币种的回显展示
      showJsCodeBlock: false, // 代码块是否显示
      hasQuota: false, // 物流控件是否有可以用次数
    }
  },
  computed: {
    productRegisterDisplayName(){
      return this.value.filter(item => item.isRegister)[0].displayName;
    },
    // 根据fieldMode筛选后的字段
    filterFields(){
      let groupFields = this.availableFields.filter(item => item.isSystem == this.fieldGroup);

      // 系统字段由于需要保证唯一性，需要剔除已存在的字段
      if(this.fieldGroup == 1){
        groupFields = groupFields.filter(f => this.value.findIndex(v => v.formType == f.formType) == -1);
      }

      return groupFields;
    },
    // 是否为空
    isEmpty(){
      return !Array.isArray(this.value) || this.value.length == 0;
    },
    // 已隐藏字段
    hiddenFields() {
      return this.value.filter(item => item.isHidden == 1)
    },
    hiddenFieldsAll() {
      if (!this.value.find(field => field.setting.isSubForm)) {
        return this.hiddenFields
      }
      return this.value.flatMap(field => {
        if(field.setting.isSubForm) {
          let arr = field.isHidden == 1 ? [field] : []
          return [...arr, ...(field.subFormFieldList || []).filter(field => field.isHidden == 1)]
        }
        return field
      }).filter(field => field.isHidden == 1)
    },
    // 未隐藏字段
    unHiddenFields() {
      return this.value.filter(item => item.isHidden !== 1);
    },
    // 当前字段是否是公用字段
    isCommonField() {
      return this.currField && !!this.currField.isCommon;
    },
    // 是否开启工单编号灰度
    isCustomTaskNo() {
      const RootWindow = getRootWindow(window)
      return RootWindow.grayAuth?.customTaskNo || false
    },
    // 是否有客户关联表单
    isHasRelationCustomer(){
      return this.fieldControls.filter(item=>item.typeKey == 0)[0].field.some(f=>f.formType == 'relationCustomer' )
    },
    // 是否有产品关联表单
    isHasRelationProduct(){
      return this.fieldControls.filter(item=>item.typeKey == 0)[0].field.some(f=>f.formType == 'relationProduct' )
    },
    // 是否展示多语言预览
    isShowSetLang() {
      return this.isOpenMultiLanguage && isMultiLangModules(this.mode)
    },
    // 当前表单连接器字段个数
    connectorFieldsLength() {
      let connectorFields = []
      for (const f of this.value) {
        if(f.formType === 'connector') {
          connectorFields.push(f)
        }
      }
      return connectorFields.length
    },
    // 是否开备件返还灰度
    isSparePartsReturnExpense() {
      const RootWindow = getRootWindow(window)
      return Boolean(RootWindow.grayAuth?.TASK_SPARE_PART_RETURN)
    },
    // 是否开启服务商灰度
    isProviderManager() {
      const RootWindow = getRootWindow(window)
      return RootWindow.grayAuth?.providerManager ?? false
    },
  },
  watch: {
    value(newValue, oldValue) {
      let { currField } = this;
      if(currField){
        this.currField = newValue.find(item => item.id === currField.id);
      }
      this.smoothingDateFieldDateType(newValue, oldValue);
    }
  },
  methods: {
    smoothingDateFieldDateType(newValue, oldValue) {

      if (!newValue || !oldValue) {
        return
      }

      if (isEmpty(newValue)) {
        return
      }

      this.smoothingDateFieldDateTypeImpl()

    },
    smoothingDateFieldDateTypeImpl() {

      let dateFields = this.value.filter(field => isDateField(field) || isDatetimeField(field))

      dateFields.forEach(field => {
        if (isFalsy(field?.setting?.dateType)) {
          return
        }
        const isDateHour = Boolean(field?.setting?.isDateHour)
        field.setting.dateType = isDateHour ? 'yyyy-MM-dd HH' : field.setting.dateType
      })

    },
    /** 触发input事件 */
    emitInput(value){
      this.$emit('input', value)
    },
    /** 更新字段依赖 */
    updateDependencies(target){
      let fieldMap = {};
      for(let i = 0; i < this.value.length; i++) {
        fieldMap[this.value[i].fieldName] = this.value[i];
      }

      // 合并数据
      target
        .filter(i => i.dependencies && Object.keys(i.dependencies).length > 0)
        .forEach(f => {
          let field = fieldMap[f.fieldName]

          if(null != field){
            this.$set(field, 'dependencies', f.dependencies)
          }
        })
    },
    /** 当field字段变动时，检测逻辑项 */
    checkLogicalField(){
      let value = this.value;
      let removeArr = [];
      let fieldMap = value.reduce((o, field, index) => (o[field.fieldName] = {field, index}) && o, {});

      for(let i = 0; i < value.length; i++){
        let field = value[i];
        let dependencies = field.dependencies || {};
        if(isEmpty(dependencies)) continue;

        Object.keys(dependencies).forEach(fieldName => {
          let fm = fieldMap[fieldName];
          if(fm == null) return delete dependencies[fieldName];

          // 在该字段下面需要去除逻辑项
          if(fm.index > i){
            let dep = dependencies[fieldName];
            if(Array.isArray(dep) && dep.length > 0) {
              removeArr.push([fm.field, field])
            }

            delete dependencies[fieldName];
          }
        })
      }

      if(removeArr.length > 0) this.showLogicalNotification(removeArr);
      this.emitInput(value);
    },
    /**
     * 删除与某字段关联的逻辑显示项
     * @param {Object} depField - 待删除依赖的字段
     * @param {boolean} clear - 是否是删除所有依赖。 true - 删除所有， false - 只删除option的依赖
     */
    deleteDependencies(depField, clear = true){
      this.$nextTick(() => {
        let allFields = this.value;
        let fieldName = depField.fieldName;
        let values = depField.options.map(i => i.value);
        let removeArr = []
        // 删除与该字段关联的字段
        allFields.forEach(field => {
          let dependencies = field.dependencies || {};
          if(isEmpty(dependencies) || null == dependencies[fieldName]) return;

          let dep = dependencies[fieldName];
          if(!Array.isArray(dep)) dep = [];

          // 删除所有依赖项
          if(clear) {
            if(dep.length > 0) removeArr.push([depField, field])
            return delete dependencies[fieldName]
          }

          dependencies[fieldName] = dep
            .map(val => {
              let newVal = values.indexOf(val) >= 0 ? val : null;
              if(newVal == null) removeArr.push([depField, field, val])

              return newVal;
            })
            .filter(i => i != null);
        })

        if(removeArr.length > 0) this.showLogicalNotification(removeArr);
      })
    },
    /** 显示逻辑显示变动提示 */
    showLogicalNotification(arr = []){
      Platform.notification({
        type: 'warning',
        title: i18n.t('common.form.setting.showLogicalNotificationTitle'),
        duration: 0,
        message: (function(h){
          let fieldNodes = arr.map(arr => {
            let [p, r, v] = arr;
            let suffix = v == null ? null : <strong>[{v}]</strong>
            return <p><strong>{p.displayName}</strong> {suffix} -- <strong>{r.displayName}</strong></p>
          });

          return (
            <div class="form-design-notification">
              <p>{i18n.t('common.form.setting.showLogicalNotificationDes')}</p>
              <div class="form-design-notification-content">{fieldNodes}</div>
            </div>
          );
        })(this.$createElement)
      })
    },
    /** 开始插入字段 */
    beginInsert(field, event) {
      // 禁止拖拽
      if (this.draggingDisable(field)) return;

      // 拖拽客户关联、产品关联字段、工单引用表单
      if(field.formType == 'relationCustomer' || field.formType == 'relationProduct' || field.formType == 'relationReplacementPart' || field.formType == 'relationTask') {
        if(this.mode == 'event'){
          this.openRelatedOptionsDialog(field)
        }else{
          if(field.formType == 'relationTask') {
            // 工单引用表单
            this.$eventBus.$emit('task_form_design_relation_form_set', field);
          }else{
            this.$eventBus.$emit('task_form_design_relation_options_set', field);
          }
        }
        return;
      }

      // 屏蔽非鼠标左键的点击事件
      if(event.button !== 0) return;

      // 限制字段数量
      if (this.value.length >= this.max) {
        return Platform.alert(i18n.t('common.form.setting.formFieldMaxCountTips', {data1:this.max}))
      }

      // 限制电子签名字段数量
      let autographFields = this.value.filter(field => field.formType == 'autograph');
      if(autographFields.length >= this.autographMax && field.formType === 'autograph') {
        return Platform.alert(i18n.t('common.form.setting.formSignFieldMaxCountTips', {data1:this.autographMax}));
      }


      // 限制富文本数量
      let richTextFieldsMax = this.value.filter(field => field.formType == 'richtext');
      console.log(richTextFieldsMax, this.value, 'this.valuethis.valuethis.value')
      if(richTextFieldsMax.length >= this.richTextFieldsMax && field.formType === 'richtext') {
        return Platform.alert(i18n.t('common.form.setting.formSignFieldMaxCountTips', {data1:this.richTextFieldsMax}));
      }

      let dragEvent = this.$data.$dragEvent;
      let target = event.target.closest('.form-design-field');
      let dragRect = target.getBoundingClientRect();

      dragEvent.target = target;
      dragEvent.offsetY = event.clientY - dragRect.top;
      dragEvent.offsetX = event.clientX - dragRect.left;
      dragEvent.prevClientY = event.clientY;
      dragEvent.mode = 'insert';
      dragEvent.insertFieldOption = field;
      dragEvent.initGhost = false;

      this.currField = null;
      this.insertedField = null;
      this.originValue = cloneDeep(this.value);

      // 监听鼠标移动事件
      document.addEventListener('mousemove', this.handleDragging)
      document.addEventListener('mouseup', this.handleDragEnd)
    },
    /** 开始拖拽 */
    beginSort(field, event) {
      // 屏蔽非鼠标左键的点击事件
      if(event.button !== 0) return;

      let dragEvent = this.$data.$dragEvent;
      let target = event.target.closest('.form-design-preview');
      let dragRect = target.getBoundingClientRect();

      dragEvent.target = target;
      dragEvent.offsetY = event.clientY - dragRect.top;
      dragEvent.offsetX = event.clientX - dragRect.left;
      dragEvent.prevClientY = event.clientY;
      dragEvent.mode = 'sort';
      dragEvent.initGhost = false;

      if(this.currField && this.currField !== field) {
        // 映射关系只填写一个时，切换就清空
        if(!!this.currField.fieldMappingForm?.sourceField ^ !!this.currField?.fieldMappingForm?.sourceTable) {
          this.currField.fieldMappingForm = {}
        }
      }
      this.$set(this, 'currField', field)
      // this.currField = field;
      this.isOpenRegister && this.getType(field)
      // 监听鼠标移动事件
      document.addEventListener('mousemove', this.handleDragging)
      document.addEventListener('mouseup', this.handleDragEnd)
    },

    /** 处理拖拽 */
    handleDragging(event) {
      let dragEvent = this.$data.$dragEvent;
      let ghostEl = dragEvent.ghostEl;
      let containerEl = dragEvent.containerEl;
      let dragEl = dragEvent.target;

      // 初始化ghostEL
      if (!dragEvent.initGhost) {
        ghostEl.style.display = 'block';
        ghostEl.querySelector('.form-design__template').innerHTML = getTemplate(dragEl)
        ghostEl.style.width = `${ dragEl.offsetWidth }px`;

        if (this.currField) this.currField.dragging = true;
        dragEvent.initGhost = true;
        this.silence = true;
      }

      // 移动ghostEl
      let y = event.clientY - dragEvent.offsetY;
      let x = event.clientX - dragEvent.offsetX
      ghostEl.style.transform = `translate3d(${x}px, ${y}px, 0)`;
      dragEvent.direction = event.clientY - dragEvent.prevClientY >= 0 ? 1 : -1;
      dragEvent.prevClientY = event.clientY;

      // 判断ghostEl是否在容器内
      let containerRect = containerEl.getBoundingClientRect();
      let ghostRect = ghostEl.getBoundingClientRect();
      let inContainer = isInContainer(ghostRect, containerRect);

      if (dragEvent.mode == 'sort') {
        if (inContainer) {
          let dragIndex = this.unHiddenFields.findIndex(item => item._id == this.currField._id);
          let enterIndex = this.calcIndex(y, dragIndex);
          if(dragIndex == enterIndex) return;
          let formType = ['relationProduct'];
          if(this.mode == 'product_register'){
            if((!this.value[dragIndex].isRegister && !this.value[enterIndex].isRegister && formType.indexOf(this.value[dragIndex].formType) === -1 && formType.indexOf(this.value[enterIndex].formType) === -1) || (formType.indexOf(this.value[dragIndex].formType) > -1 && formType.indexOf(this.value[enterIndex].formType) > -1) || (this.value[dragIndex].isRegister && enterIndex === 0)){
              this.sort(dragIndex, enterIndex);
            }
          }else{
            this.sort(dragIndex, enterIndex);
          }
        }
        return;
      }

      if (dragEvent.mode == 'insert') {
        // 已经插入但是当前拖拽元素不在容器内，删除该字段
        if (!inContainer && this.insertField) {
          this.insertedField = null;
          this.currField = null;
          this.emitInput(this.originValue);
          return;
        }

        if (inContainer) {
          // 如果已经插入，对字段进行排序
          if (this.insertedField) {
            let dragIndex = this.unHiddenFields.findIndex(item => item._id == this.insertedField._id);
            let enterIndex = this.calcIndex(y, dragIndex);
            let num = 0;
            this.value.forEach((item, index)=>{
              if(item.formType == 'relationProduct'){
                num = index
              }
            })
            if(this.mode && this.mode == 'product_register'){
              if(enterIndex > num) {
                this.sort(dragIndex, enterIndex);
              } else {
                this.sort(dragIndex, num + 1)
                // Platform.alert('只能插入到产品关联字段以下')
              }
            }else{
              this.sort(dragIndex, enterIndex);
            }

            return;
          }

          // 插入字段
          dragEvent.direction = 0;
          let insertIndex = this.calcIndex(y);
          let newField = this.insertField(dragEvent.insertFieldOption, this.value, insertIndex)
          this.insertedField = newField;
        }
      }
    },
    /** 结束拖拽 */
    handleDragEnd() {
      // 清空鼠标事件
      document.removeEventListener('mousemove', this.handleDragging)
      document.removeEventListener('mouseup', this.handleDragEnd)

      let dragEvent = this.$data.$dragEvent;
      dragEvent.ghostEl.style.display = 'none';

      // 检查逻辑字段
      if(dragEvent.mode == 'sort' && dragEvent.initGhost){
        this.checkLogicalField()
      }

      if (this.currField) this.currField.dragging = false;
      this.silence = false;

    },
    /** 计算当前位置索引 */
    calcIndex(distance, currIndex = -1) {
      let dragEvent = this.$data.$dragEvent;
      let containerEl = dragEvent.containerEl;
      let previewDoms = Array.prototype.slice.call(dragEvent.containerEl.children);
      let containerRect = containerEl.getBoundingClientRect();

      let offsetTop = distance - containerRect.top + containerEl.scrollTop;
      let direction = dragEvent.direction;

      // 如果是向上移动 或 插入时
      if (direction <= 0) {
        for (let i = 0; i < previewDoms.length; i++) {
          let dom = previewDoms[i];
          if (dom.offsetTop + (dom.offsetHeight / 2) > offsetTop) {
            // 如果前一位置是当前位置，直接返回前一位置
            return i - 1 == currIndex ? currIndex : i;
          }
        }
      }

      // 如果是向下移动
      if (direction > 0) {
        let index = -1;
        let ghostEl = dragEvent.ghostEl;
        offsetTop += ghostEl.offsetHeight;

        for (let i = 0; i < previewDoms.length; i++) {
          let dom = previewDoms[i];
          if (dom.offsetTop + (dom.offsetHeight / 2) < offsetTop + dragEvent.offsetY) {
            index = i;
          }
        }
        // 如果后一位置是当前位置，直接返回后一位置
        return index + 1 == currIndex ? currIndex : index;
      }

      return -1;
    },
    /** 字段排序 */
    sort(dragIndex, enterIndex) {
      if (dragIndex < 0 || enterIndex < 0 || dragIndex == enterIndex) return;

      let arr = cloneDeep(this.unHiddenFields);

      let distance = dragIndex < enterIndex ? 1 : 0
      let dragField = arr[dragIndex]; // 拖拽的字段
      let enterField = arr[enterIndex]; // 目标字段

      arr.splice(dragIndex, 1);
      let insertIndex = arr.indexOf(enterField);
      arr.splice(insertIndex + distance, 0, dragField);

      let newArr = [...arr, ...this.hiddenFields]
      this.emitInput(newArr)
      this.chooseField(dragField)
    },
    /** 选中字段 */
    chooseField(field) {
      if (field.formType == 'logistics') {
        this.currField = null
        this.$nextTick(() => {
          this.currField = field
        })
      } else {
        this.currField = field
      }

      this.isOpenRegister && this.getType(field)
      this.$nextTick(() => {
        let draggingEl = this.$el.querySelector('.form-design-selected');
        // let dragEvent = this.$data.$dragEvent;
        // let containerEl = dragEvent.containerEl;
        let containerEl = findParentElementWithClassName(
          draggingEl,
          'form-preview'
        );
        let visible = isVisibility.call(this, draggingEl, containerEl);

        if (!visible) {
          let scrollTop = draggingEl.offsetTop + draggingEl.offsetHeight - containerEl.offsetHeight;
          containerEl.scrollTop = scrollTop;
        }
      })
    },

    getType(field){
      let map = this.mode == 'product' || this.mode == 'customer';
      if(!map) return;
      getType({
        table:'register',
        type:field.formType
      }).then(r=>{
        if(r.status == 0 && r.data){
          this.mapList = r.data
        }
      })
    },
    /** 选中产品注册字段 */
    async checkField(item, field, name) {
      if(!item) return false
      let tip = i18n.t('common.form.setting.checkFieldTips', {data1:name});
      if (!await Platform.confirm(tip)) return;
      this.value.forEach(item=>{
        if(item.isRegister)
          item.isRegister = 0
        if(item.placeHolder == '产品注册标识')
          item.placeHolder = ''
      });
      field.isRegister = item
      field.isNull = 0
      field.placeHolder = i18n.t('common.form.setting.productRegisterSymbol')
      this.$forceUpdate()
      let dragIndex = this.unHiddenFields.findIndex(item => item._id == this.currField._id);
      this.sort(0, dragIndex);
      this.$nextTick(()=>{
        let dragIndex = this.unHiddenFields.findIndex(item => item._id == this.currField._id);
        if(dragIndex > 0)
          this.sort(dragIndex - 1, 0);
      })

    },

    /** 删除字段 */
    async deleteField(item) {
      let tip = ''
      if(item.isSystem == 0) {
        tip = item.setting?.isRelationQuality ? i18n.t('common.form.setting.deleteFieldTips1') : i18n.t('common.form.setting.deleteFieldTips2')
      } else {
        tip = i18n.t('common.form.setting.deleteFieldTips3')
      }
      if (!await Platform.confirm(tip)) return;

      let value = this.value;
      let index = value.indexOf(item);

      if (index >= 0 && !item.setting?.isRelationQuality) {
        // 如果是选中的字段，清除选中
        if (this.currField == item) this.currField = null;

        value.splice(index, 1);

        this.deleteDependencies(item);
        this.emitInput(value)
      }
    },
    /** 隐藏字段 */
    async hiddenField(item) {
      let tip = item.isSystem == 0 ? i18n.t('common.form.tip.hideFieldTips1') : i18n.t('common.form.tip.hideFieldTips2')
      if (!await Platform.confirm(tip)) return;

      let value = this.value;
      let index = value.indexOf(item);
      value[index].isHidden = value[index].isHidden == 1 ? 0 : 1;

      this.emitInput(value)
    },
    async deleteUser(item, callback) {
      let result = await checkUser({ id : item.id })
      let isSuccess = result.status == 0
      // 是否成功
      if (!isSuccess) {
        console.warn('Caused: checkUser Function result is fail')
        return false
      }
      // 是否需要审批
      let isNeedApproval = result.data && result.data.show == 1
      if (!isNeedApproval) {
        callback(item);
        return true;
      }

      // 是审批人
      let confirm = await this.$platform.confirm(i18n.t('common.form.setting.deleteUserTips'));
      // 取消该id对应的人员字段必填后，指向该人员的审批流程变为“无需审批”
      if(confirm) return callback(item)
    },

    /** 添加新字段 */
    insertField(option = {}, value, index, isRelatedField) {
      // 拖进来的是公共字段
      let isDragCommon = option.isCommon == 1;

      let fieldName = option.fieldName
      let newField = new FormField({
        ...option,
        formType: option.formType,
        displayName: option.name,
        fieldName: option.fieldName,
        isSystem: option.isSystem,
        isDragCommon: isDragCommon ? 1 : 0,
        setting: (isDragCommon || isRelatedField) ? option.setting : {}
      });

      if (newField.formType == 'logistics') {
        newField.isNull = 1;
        newField.setting = {
          ...newField.setting,
        }

      }
      // 工程师表单设计器的工程师资质默认多选，并且只能选择10条
      if(newField.formType === 'engineerQuality') {
        newField.isMulti = true;
        newField.setting = {
          isMulti: true,
          limit: 10,
        }
      }
      // 服务商表单设计器图片展示默认最多添加6条
      if(newField.formType === 'imageDisplay') {
        newField.isMulti = true;
        newField.setting = {
          isMulti: true,
          limit: 6,
          accept: 'image/*'
        }
      }

      if(!fieldName) newField.isNewField = true

      let arr = cloneDeep(value ? value : this.value);
      index == null ? arr.push(newField) : arr.splice(index, 0, newField);
      this.emitInput(arr)
      // 选中新添加的字段
      this.chooseField(newField);
      return newField;
    },
    /** 立即插入字段 */
    immediateInsert(field, event, isRelatedField = false) {
      // 点击拖拽未开通的组件
      if(field.notOpened) return this.openTheConsultation();
      // 判断连接器字段数量
      if (this.connectorFieldsLength >= this.maxConnectorFields && field.formType === 'connector') return Platform.alert(`单个表单最多支持${this.maxConnectorFields}个连接器字段`)

      // 禁止拖拽
      if (this.draggingDisable(field)) return;

      let dragEvent = this.$data.$dragEvent;
      if (dragEvent) dragEvent.direction = 0;

      // 限制字段数量
      if (this.value.length >= this.max) return Platform.alert(i18n.t('common.form.setting.formFieldMaxCountTips', {data1:this.max}))

      // 拖拽客户关联、产品关联字段
      if(!isRelatedField && (field.formType == 'relationCustomer' || field.formType == 'relationProduct' || field.formType == 'relationReplacementPart' || field.formType == 'relationTask') && field?.isCommon !== 1) {
        if(this.mode == 'event'){
          this.openRelatedOptionsDialog(field)
        }else{
          if(field.formType == 'relationTask') {
            this.$eventBus.$emit('task_form_design_relation_form_set', field);
          }else{
            this.$eventBus.$emit('task_form_design_relation_options_set', field);
          }
        }
        return;
      }

      let num = 0, newField;
      this.value.forEach((item, index)=>{
        if(item.formType == 'relationProduct'){
          num = index
        }
      })
      // eslint-disable-next-line no-cond-assign
      if(this.mode == 'product_register' && field.formType == 'relationProduct'){
        field.placeHolder = i18n.t('common.form.type.relationProduct')
        newField = this.insertField(field, this.value, num + 1, isRelatedField);
      }else{
        newField = this.insertField(field, this.value, this.value.length, isRelatedField);
      }

      this.insertedField = newField;

      this.$nextTick(() => {

        this.currField = newField;

        const preViewContainerEl = this.$data.$dragEvent.preViewContainerEl

        if (preViewContainerEl) {
          preViewContainerEl.scrollTop = 100000
        }

      })
    },
    cloneData(option) {
      // 拖进来的是公共字段
      let isDragCommon = option.isCommon == 1;
      let fieldName = option.fieldName;

      let newField = new FormField({
        ...option,
        formType: option.formType,
        displayName: option.name,
        fieldName,
        isSystem: option.isSystem,
        isDragCommon: isDragCommon ? option.isCommon : 0,
        setting: isDragCommon ? (option.setting || {}) : {}
      });

      if (!fieldName) {
        newField.isNewField = true
      }

      return newField;
    },
    scrollPreviewList(e) {
      let containerEl = this.$data.$dragEvent.containerEl;

      let {pixelY} = normalizeWheel(e);
      containerEl.scrollTop += pixelY;
    },
    // 获取角色列表
    getRoleListreq() {
      this.$http.get('/setting/role/list', {pageSize: 0 }).then(res => {
        const { list } = res;
        this.roleList = list;
      }).catch(err => console.error('err', err));
    },
    // 获取服务商角色
    async getproviderRoleList() {
      try {
        if(!['task', 'task_receipt'].includes(this.mode) || !this.isProviderManager) return;

        const { data } = await getRoleServiceTree()
        this.providerRoles = data?.children?.[0]?.children ?? [];
      } catch (e) {
        console.error(e)
      }
    },
    // 获取物料清单
    async getMaterialAllFields() {
      try {
        let url = {
          product_menu: getProductMaterialFields,
          fault_library: getMaterialAllFields,
          task_receipt: getTaskMaterialFields,
        }
        
        const res = await url[this.mode]();

        if (!res.success) return Platform.toast(res.message, 'error');

        // 特殊字段需过滤 服务商网点，产品类型
        let special_fields = [...RELATION_DISABLE_FIELDS, 'serviceProvider', 'productCatalog']

        let { data, result } = res;

        let fields = (data || result || [])
          .filter(item => {
            return !special_fields.includes(item.formType);
          })
          .map(field => {
            return {
              ...field,
              id: null, // 去掉原字段id，由后端生成
              formType: 'relationMaterialsBill',
              setting: {
                ...(field.setting || {}),
                originalFormType: field.formType, // 存储原本的类型
              },
            };
          });

        this.materialFiels = fields;
      } catch (error) {
        console.log('getMaterialAllFields=>', error);
      }
    },
    /** 获取产品关联查询字段关联项数据 */
    contractProductFields() {
      getProductFieldList()
        .then(res => {
          const { data = [] } = res;
          // 过滤自定义字段且非禁用类型
          let fields = data.filter(
            field => RELATION_DISABLE_FIELDS.indexOf(field.formType) == -1
          );
          this.productFields = fields;
        })
        .catch(err => console.error('err', err));
    },
    /** 获取服务商子表单关联项数据 */
    getServiceProviderFields() {
      getServiceProviderFields()
        .then(res => {
          const { result = [] } = res;
          this.serviceProviderFields = result;
        })
        .catch(err => console.error('err', err));
    },

    // 获取合同备件关联查询字段关联项数据
    contractSparePartFields() {
      getSparepartFields()
        .then(res => {
          const { data = [] } = res;
          // 过滤自定义字段且非禁用类型
          let fields = data.filter(
            field => RELATION_DISABLE_FIELDS.indexOf(field.formType) == -1
          );
          this.sparePartFields = fields;
        })
        .catch(err => console.error('err', err));
    },

    // 获取服务项目表单字段
    getServiceItemAllFields(){
      servicePriceListInfo().then(res => {
        if(res.status == 0) {
          this.serviceItemFields = res.data.fieldInfos
        }
      })
    },
    // 获取工单系统字段
    async getAllFieldsReq() {
      try {
        const params = {
          typeId:'',
          tableName:'task',
          isFromSetting: true
        }
        const fields = await getAllFields(params);
        this.taskSystemFields = (fields || []).filter(item=> item.fieldName !== 'attachment');
      } catch (err) {
        console.error('err', err)
      }
    },

    renderTabHeader({ name, type }){
      return (
        <div class="form-design-tabs">
          <div class="form-design-tab">
            {name}
            {
              type === 'system'
              && <el-tooltip
                placement="top"
                class="form-design-tab-tips"
                content={i18n.t('common.form.setting.renderTabHeaderTips')}>
                <i class="el-icon-question el-tooltip"></i>
              </el-tooltip>
            }
          </div>
        </div>
      );
    },
    renderFieldList(fields) {

      const { setHoverEffect, hideHovered } = FormUtil.formPreviewCompHoverMethodsEffect;

      if (fields.length == 0) {
        return (
          <div class="form-design-field-empty">
            { this.fieldGroup == 0 ? i18n.t('common.form.setting.renderFieldListTips1') : i18n.t('common.form.setting.renderFieldListTips2')}
          </div>
        )
      }

      return fields.map(field => {
        const showLabel = (field.label && field.formType !== 'logistics') || (field.formType === 'logistics' && !this.hasQuota);
        return (
          <div
            class={[
              'form-design-field-wrap',
              {
                'disabled': this.draggingDisable(field)
              }
            ]}
            onMouseover={setHoverEffect}
            onDragend={hideHovered}
            onMouseleave={hideHovered}
            onClick={e => this.immediateInsert(field, e)}
          >
            <div class="form-design-field form-design__ghost">
              <span class="anticon">
                <i class={['iconfont', field.previewIcon || `icon-fdn-${(field.formType == 'planStartTime' || field.formType == 'planEndTime') ? 'datetime': field.formType}`]}></i>
              </span>
              <span class="field-name">
                {field.name}
              </span>
              { showLabel && <span class="field-label">{field.label}</span>}
            </div>
          </div>
        )
      });
    },
    renderSettingPanel(h){
      let fieldSetting = createSettingComp.call(this, h, this.currField);
      // if(null == fieldSetting) return null;
      return (
        this.isShow && <div
          class={['form-design-setting', this.isCommonField && 'form-design-setting-disabled']}
          key="form-design-setting">
          {   this.renderFieldCommonSetting() }
          { fieldSetting }
        </div>
      )
    },
    // 渲染已隐藏字段弹窗dom
    renderBaseModal(h){
      if(!this.show) return null;
      const scopedSlots = {
        default:({row, column})=>{
          return <el-button type="text" size="small" onClick={()=>this.onRestoreField(row)}>{i18n.t('common.form.hideModal.revert')}</el-button>
        }
      }
      return (
        <base-modal
          appendToBody={ true }
          class="base-hidden-modal"
          title={i18n.t('common.form.tip.haveHideField')}
          show={ this.show }
          onClose={ this.onCloseBaseModal }
          width="400px"
        >
          <el-table data={this.hiddenFieldsAll} header-row-class-name="base-table-header-v3" row-class-name="base-table-row-v3" border>
            <el-table-column prop="displayName" label={i18n.t('common.form.tip.haveHideField')}/>
            <el-table-column label={i18n.t('common.base.operation')} width="100" scopedSlots={ scopedSlots }/>
          </el-table>
        </base-modal>
      );
    },
    updateOptions(field, event) {
      if(!field.setting.customerOption) return;
      field.setting.customerOption[event.prop] = event.value;
    },
    /**
     * @description 恢复已隐藏字段
    */
    async onRestoreField(row) {
      let value = this.value;
      let parentFieldId = row.parentFieldId
      if (parentFieldId) {
        value = value.find(v => v.fieldName === parentFieldId)?.subFormFieldList || []
      }
      let index = value.indexOf(row);
      value[index].isHidden = value[index].isHidden == 1 ? 0 : 1;

      this.emitInput(this.value)
      this.$platform.notification({
        title: i18n.t('common.base.tip.operationSuccess'),
        type: 'success',
      });
    },
    /**
     * @description 关闭弹窗
    */
    onCloseBaseModal() {
      this.show = false;
    },
    /**
     * @description 显示弹窗
    */
    onShowBaseModal() {
      if(this.hiddenFieldsAll.length == 0) return this.$platform.confirm(i18n.t('common.form.tip.thereisNoHideField'));
      this.show = true;
    },
    /**
    * @description 禁止拖拽
    */
    draggingDisable(field) {
      let richtextCount = 0;
      let boolean = false
      let onlyOne = ['customer', 'customerAddress', 'linkman', 'product', 'subSparePart', 'productWarrantyService', 'projectCustomer', 'projectProduct', 'remarkProduct']
      this.value.forEach(v => {
        if(v.fieldName == field.fieldName){
          boolean = true;
        }
        if(v.formType == 'richtext'){
          richtextCount ++ ;
        }

        if(onlyOne.includes(field.formType) && v.formType == field.formType) {
          boolean = true;
        }
      });
      // 富文本数量限制
      if(field.formType == 'richtext' && richtextCount >= this.richTextFieldsMax){
        boolean = true;
      }
      // 连接器字段数量限制
      if(field.formType == 'connector' && this.connectorFieldsLength >= this.maxConnectorFields){
        boolean = true;
      }
      return boolean;
    },
    /**
    * @description 渲染公共字段特有的设置内容
    */
    renderFieldCommonSetting() {
      return this.isCommonField && (
        <div class="common-field-setting">
          <h4>{i18n.t('common.form.publicField')}</h4>
          <div class="common-field-setting-btn">
            <el-button onClick={this.cancelFieldCommonSetting} disabled={this.isDisableCommonField}>{i18n.t('common.form.setting.cancelPublicFieldBtn')}</el-button>
            <el-button type="primary" onClick={this.openFieldSettingModal}>{i18n.t('common.form.setting.editFieldOptionBtn')}</el-button>
          </div>
        </div>
      )
    },
    /**
    * @description 渲染公共字段修改控件配置弹窗
    */
    renderFieldCommonSettingModal(h) {
      let fieldSetting = createSettingComp.call(this, h, this.currField);
      return this.fieldSettingModal.visible && (
        <div class="field-setting-modal">
          <base-panel
            show={ this.fieldSettingModal.visible }
            onClose={ this.closeFieldSettingModal }
            title={i18n.t('common.form.setting.editFieldOptionBtn')}
            width="350px"
            re
          >
            <div class="base-panel-content">
              <div class="form-design-warning">
                <i class="iconfont icon-warning-circle-fill"></i>
                <span>{i18n.t('common.form.setting.renderFieldCommonSettingModalDes')}</span>
              </div>
              { fieldSetting }
            </div>
            <div class="base-panel-footer" slot="footer">
              <el-button onClick={ this.closeFieldSettingModal }>{i18n.t('common.base.cancel')}</el-button>
              <el-button type="primary" onClick={ this.saveFieldSetting } disabled={ this.fieldSettingModal.pending }>{i18n.t('common.base.save')}</el-button>
            </div>
          </base-panel>
        </div>
      )
    },
    /**
    * @description 取消当前字段公共字段属性
    */
    async cancelFieldCommonSetting() {
      let confirm = await this.$platform.confirm(i18n.t('common.form.setting.cancelFieldCommonSettingTips', {data1:this.currField.displayName}));
      if(!confirm) return;

      this.$emit('cancelPublicFieldSetting', this.currField);
    },
    /**
    * @description 打开修改控件配置弹窗
    */
    openFieldSettingModal() {
      this.fieldSettingModal.backupField = cloneDeep(this.currField);
      this.fieldSettingModal.visible = true;
    },
    /**
    * @description 取消修改控件配置
    */
    closeFieldSettingModal() {
      this.currField = cloneDeep(this.fieldSettingModal.backupField);
      this.fieldSettingModal.visible = false;
    },
    /**
    * @description 修改公共字段配置
    */
    async saveFieldSetting() {
      let confirm = await this.$platform.confirm(i18n.t('common.form.setting.saveFieldSettingTips'));
      if(!confirm) return;

      this.fieldSettingModal.pending = true;

      this.currField = cloneDeep(this.currField)

      this.isShow = false
      this.$nextTick(() => {
        this.isShow = true
      })
      this.$emit('updatePublicFieldSetting', this.currField);
    },
    /**
    * @description 打开关联项设置弹窗
    * 从左侧基础控件拖入客户关联字段或者产品关联字段时打开弹窗
    */
    openRelatedOptionsDialog(field) {
      
      this.relationField = field;
      
      // 关联项字段列表
      let relationTypeOption = this.relationOptionsMap[field.formType];
      let relationOptions = this.relationOptions[relationTypeOption];
      
      // 事件、工单表单关联产品字段过滤某些字段
      const modes = ['event', 'task']
      
      if (modes.includes(this.mode)) {
        
        const fieldNameByVersionShowMap = {
          // 产品类型
          // type: this._isShowProductType,
          // 产品模板
          productTemplate: this._isShowProductTemplate,
          // 质保开始时间
          qualityInfoStartTime: this._isShowProductQuality,
          // 质保结束时间
          qualityInfoEndTime: this._isShowProductQuality,
          // 质保状态
          qualityInfoStatus: this._isShowProductQuality
        }
        
        relationOptions = relationOptions.filter(item => {
          
          const isShow = fieldNameByVersionShowMap[item?.fieldName]
          if (isNotUndefined(isShow)) {
            return isShow
          }
          
          return true;
          
        })?.filter(item => !['logistics'].includes(item.formType)) ?? [] // 关联字段过滤物流控件

      }
      
      let isCustomer = field.formType == 'relationCustomer';
      this.$refs.relationOptionsModal.open(relationOptions, isCustomer);
    },
    /**
    * @description 关联项设置成功
    */
    relationOptionsConfirm(options) {
      for (let index = 0; index < options.length; index++) {
        const setting = options[index];
        const field = cloneDeep(this.relationField);

        // 设置该关联查询字段的标题为关联项标题
        field.name = setting.displayName;

        // 删除setting多余字段
        delete setting.displayName;
        field.setting = setting;

        // 加延时异步是因为form-design的insertField方法更新value异步会导致选择多个关联项时只能插入一个
        setTimeout(() => {
          this.immediateInsert(field, null, true);
        }, 0)
      }
    },
    /**
    * @description 获取客户关联查询字段关联项数据
    */
    getCustomerFields() {
      CustomerApi.getCustomerFields({ isFromSetting: false })
        .then(res => {
          if (res.succ) {
            // 过滤自定义字段且非禁用类型
            let fields = res.data.filter(field => field.isSystem == 0 &&  [...RELATION_DISABLE_FIELDS, 'richtext'].indexOf(field.formType) == -1);
            // TODO-bdz  表单统一维护
            fields.unshift({
              'fieldId':'serialNumber',
              'tableName':'customer',
              'fieldName':'serialNumber',
              'displayName':i18n.t('common.fields.customerNo.displayName'),
              'isSystem':'0',
              'isSearch':'1',
              'isAppShow':'0',
              'formType':'text'
            }, {
              'fieldId':'tags',
              'tableName':'customer',
              'fieldName':'tags',
              'displayName':i18n.t('common.fields.serviceDept.displayName'),
              'isSystem':'0',
              'isSearch':'1',
              'isAppShow':'0',
              'formType':'selectMulti'
            }, {
              'fieldId':'customerManager',
              'tableName':'customer',
              'fieldName':'customerManager',
              'displayName':i18n.t('common.fields.customerUser.displayName'),
              'isSystem':'0',
              'isSearch':'1',
              'isAppShow':'0',
              'formType':'text'
            })

            this.relationOptions.customerFields = fields;
          }
        })
        .catch(err => console.warn(err));
    },
    /**
        * @description 获取产品关联查询字段关联项数据
        */
    getProductFields() {
      ProductApi.getProductFields({ isFromSetting: false })
        .then(res => {
          if (res.succ) {
            // 过滤自定义字段且非禁用类型
            let fields = res.data.filter(field => field.isSystem == 0 &&  [...RELATION_DISABLE_FIELDS, 'richtext'].indexOf(field.formType) == -1);
            // 过滤不能编辑的自定义字段 不展示（是否重复报修）
            fields = fields.filter(field => field.setting?.isEdit != 0)

            // TODO-bdz  表单统一维护
            fields.unshift({
              'fieldId':'serialNumber',
              'tableName':'customer',
              'fieldName':'serialNumber',
              'displayName':i18n.t('common.fields.productNo.displayName'),
              'isSystem':'0',
              'isSearch':'1',
              'isAppShow':'1',
              'formType':'text'
            }, {
              'fieldId':'type',
              'tableName':'customer',
              'fieldName':'type',
              'displayName':i18n.t('common.fields.productType.displayName'),
              'isSystem':'0',
              'isSearch':'1',
              'isAppShow':'1',
              'formType':'select'
            })

            this.relationOptions.productFields = fields;
          }
        })
        .catch(err => console.warn(err));
    },
    /**查询物流控件是否还有剩余可使用次数  */
    async checkLogisticsQuota() {
      try {
        this.hasQuota = await getLogisticsQuotaDetail();
      } catch (error) {
        console.log('error', error)
      } 
    },
    genRoleList(modeFields) {
      try {
        // 获取当前模块需要显示的付费控件
        let activateControlFields = getActivateControlFields(this.mode, 'role_auth').map(v => v.formType)
        // 拿到被过滤掉的付费控件
        const list = activateControlFields?.filter(item => !modeFields.includes(item)) ?? []
        return list
      } catch (error) {
        console.log('error', error)
        return []
      } 
    },
    onStart(e, fields) {
      const field = fields[e.oldDraggableIndex]
      if(field.notOpened) return this.openTheConsultation()
      this.dragging = true;
    },
    openTheConsultation() {
      this.$confirm(this.$t('common.form.tip.consultingCustomerService'), this.$t('common.base.tip.confirmTips'), {
        confirmButtonText: this.$t('superQrcode.configurationItem.consult'),
        cancelButtonText: this.$t('common.base.cancel'),
        type: 'warning'
      }).then(() => {
        postPage({
          action: 'shb.system.openChat',
          data: {},
        })
      }).catch((error) => {
        console.log(error)      
      });
    },
  },
  render(h){
    return (
      <div class="form-design">
        <div class="form-design-panel">
          <div class="form-design-left">
            {
              this.fieldControls.map(field => {
                return(
                  <div class="form-design-widget">
                    { this.renderTabHeader(field) }

                    <draggable
                      animation="180"
                      tag="div"
                      group={{
                        name: 'widget',
                        pull: 'clone',
                        put: false
                      }}
                      sort={false}
                      filter=".disabled"
                      value={field.field}
                      clone={this.cloneData}
                      class="form-design-tabs-content"
                      onStart={(e) => {
                        this.onStart(e,field.field)
                      }}
                      onEnd={() => {
                        this.dragging = false;
                        console.log('onEndonEnd----')
                      }}
                    >
                      {this.renderFieldList(field.field)}
                    </draggable>
                  </div>
                )
              })
            }
          </div>
        </div>
        <div class="form-design-main">
          <div class="form-design-box">
            <div class="form-design-language-preview">
              {/* TODO 测试加了！ */}
              { this.isShowSetLang && (
                <div class="flow-preview-header">
                  <BaseLanguageDropdown class="flow-preview-header-translate" options={this.languagesList} lang={this.formPreviewLocale} onChange={this.changeLocale} />
                </div>
              ) }
            </div>
            <div class="form-design-hidden">
              { this.hiddenFieldsAll.length > 0 && (
                <p onClick={this.onShowBaseModal }><i class="iconfont icon-fdn-hidden"></i>{i18n.t('common.form.tip.showHaveHideField')}</p> )}
            </div>
            <div class="form-design-center">
              <div class={['form-design-phone', this.silence ? 'form-design-silence' : null]}>
                <form-design-preview
                  value={this.value}
                  onDelete={this.deleteField}
                  onHidden={this.hiddenField}
                  mode={this.mode}
                >
                </form-design-preview>
              </div>
            </div>
          </div>
        </div>
        { this.renderSettingPanel(h) }
        <div class="form-design-ghost" key="form-design-ghost" onWheel={this.scrollPreviewList}>
          <div class="form-design__template"></div>
          <div class="form-design-cover"></div>
        </div>
        { this.renderBaseModal(h) }
        { this.renderFieldCommonSettingModal(h) }
        { this.mode == 'event' && (this.isHasRelationProduct || this.isHasRelationCustomer) && (
          <relation-options-modal
            ref="relationOptionsModal"
            onConfirm={ this.relationOptionsConfirm }
          ></relation-options-modal>)}
      </div>
    );
  },
  async mounted(){
    this.$data.$dragEvent.ghostEl = this.$el.querySelector('.form-design-ghost');
    this.$data.$dragEvent.containerEl = this.$el.querySelector('.form-design-phone');
    this.$data.$dragEvent.preViewContainerEl = this.$el.querySelector('.form-design-preview-container');

    this.getRoleListreq();
    this.getproviderRoleList();
    // 暂时支持事件
    if(this.mode == 'event') {
      this.isHasRelationProduct && this.getProductFields()
      this.isHasRelationCustomer && this.getCustomerFields()
      this.customizedSelectOptionMax = await getSelectOptionMax({configCode: ["EVENT_SELECT_LIMIT"]});
    }

    // 获取服务商子表单关联数据
    if(this.mode !== 'service_provider' && this.mode !== 'service_engineer'){
      this.getServiceProviderFields()
    }

    if(this.mode == 'contract') {
      this.contractProductFields()
      this.contractSparePartFields()
    }
    if(this.mode == 'product_menu' || this.mode == 'task_receipt') {
      this.getMaterialAllFields()
    }

    if(this.mode == 'fault_library') {
      this.getServiceItemAllFields()
      this.contractSparePartFields()
      this.getMaterialAllFields()
    }

    if(this.mode == 'task_card') {
      this.getAllFieldsReq()
    }

    if(this.mode === 'task_receipt') {
      this.contractSparePartFields();
    }

    const showJsCodeBlock = await useJsCodeBlock()
    this.showJsCodeBlock = showJsCodeBlock.value
    
    if(['event','task', 'eventReceipt', 'task_receipt', 'product'].includes(this.mode)){
      this.checkLogisticsQuota()
    }
  },
  components: {...PreviewComponents, ...SettingComponents, RelationOptionsModal, draggable, SetLanguage}
};

export default FormDesign;
